package model.algorithms.linksMapping;

import java.util.LinkedHashMap;

import model.components.links.link.SdnLink;
import model.components.networks.sdn.SdnNetwork;
import model.components.networks.virtual.VirtualNetwork;
import model.components.nodes.node.sdn.SdnNode;
import model.components.nodes.node.virtual.VirtualNode;

public class LinksMappingAlgorithm
{	
	public static final String DISTANCE_COST = "distance";
	public static final String BW_COST = "availableBandwidth";
	
	private String name;
	public String getName(){ return name; }
	public void setName( String name ){ this.name = name; }
	
	private String costMetric;
	public String getCostMetric(){ return costMetric; }
	public void setCostMetric( String costMetric ){ this.costMetric = costMetric; }
	
	private boolean isBackupVirtualNetwork;
	public boolean isBackupVirtualNetwork(){ return isBackupVirtualNetwork; }
	public void setBackupVirtualNetwork( boolean isBackupVirtualNetwork ){ this.isBackupVirtualNetwork = isBackupVirtualNetwork; }
	
	public LinksMappingAlgorithm( String name )
	{
		this.setName( name );
	}
	
	public int[][][][] run( VirtualNetwork virtualNetwork, SdnNetwork sdnNetwork, LinkedHashMap< VirtualNode, SdnNode > nodesMapping )
	{
		double availableBWs[][] = sdnNetwork.getAvailableBWs();
		
		int normalLinksMapping[][][] = this.linksMapping( virtualNetwork, sdnNetwork, nodesMapping, availableBWs );
		
		if( normalLinksMapping == null )
			return null;
			
		int requestLinksNumber = virtualNetwork.getLinks().size();
		int substrateNodesNumber = sdnNetwork.getNodes().size();
		
		int linksMapping[][][][] = new int[ requestLinksNumber ][ substrateNodesNumber ][ substrateNodesNumber ][ 2 ];

		for( int k = 0; k < requestLinksNumber; k++ )
			for( int i = 0; i < substrateNodesNumber; i++ )
				for( int j = 0; j < substrateNodesNumber; j++ )
					linksMapping[ k ][ i ][ j ][ 0 ] = normalLinksMapping[ k ][ i ][ j ];
		
		if( this.isBackupVirtualNetwork() )
		{
			for( int k = 0; k < requestLinksNumber; k++ )
				for( int i = 0; i < substrateNodesNumber; i++ )
					for( int j = 0; j < substrateNodesNumber; j++ )
					{
						if( normalLinksMapping[ k ][ i ][ j ] != 0 )
						{
							availableBWs[ i ][ j ] = 0;
							availableBWs[ j ][ i ] = 0;
						}
					}
			
			int backupLinksMapping[][][] = this.linksMapping( virtualNetwork, sdnNetwork, nodesMapping, availableBWs );
			
			if( backupLinksMapping == null )
				return null;
			
			for( int k = 0; k < requestLinksNumber; k++ )
				for( int i = 0; i < substrateNodesNumber; i++ )
					for( int j = 0; j < substrateNodesNumber; j++ )
						if( backupLinksMapping[ k ][ i ][ j ] != 0 )
							linksMapping[ k ][ i ][ j ][ 1 ] = backupLinksMapping[ k ][ i ][ j ];
		}
		
		return linksMapping;
	}

	protected int[][][] linksMapping( VirtualNetwork virtualNetwork, SdnNetwork sdnNetwork, LinkedHashMap< VirtualNode, SdnNode > nodesMapping, double availableBWs[][] )
	{
		return null;
	}
	
	public double[][] distances( SdnNetwork substrateNetwork )
	{
		int substrateNodesNumber = substrateNetwork.getSdnNodes().size();
		double distances[][] = new double[ substrateNodesNumber ][ substrateNodesNumber ];
		
		for( int i = 0; i < substrateNodesNumber; i++ )
			for( int j = 0; j < substrateNodesNumber; j++ )
				distances[ i ][ j ] = Double.MAX_VALUE; 
		
		for( SdnLink substrateLink: substrateNetwork.getSdnLinks() )
		{
			distances[ substrateLink.getFirstNode().getNumber()  ][ substrateLink.getSecondNode().getNumber() ] = substrateLink.getDistance();
			distances[ substrateLink.getSecondNode().getNumber() ][ substrateLink.getFirstNode().getNumber()  ] = substrateLink.getDistance();
		}
		
		return distances;
	}
	
}
